package com.kdg.passwordgenerator;

import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.PlainDocument;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.prefs.Preferences;

/**
 * Created with IntelliJ IDEA.
 * User: Adrynalyne
 * Date: 9/14/13
 * Time: 9:49 PM
 * To change this template use File | Settings | File Templates.
 */
/** **/
public class GUIMain extends JFrame {

    private final Preferences userPrefs = Preferences.userRoot().node(this.getClass().getName());
    private final GUIAbout gAbout = new GUIAbout();

    private JMenuItem mExit;
    private JMenuItem mProject;
    private JMenuItem mSavePref;
    private JMenuItem mResetPref;
    private JButton btnExit;
    private JButton btnGenerate;

    private JPopupMenu mContext;
    private JMenuItem mCopy;

    private JCheckBox checkClip;
    private JCheckBox checkLetters;
    private JCheckBox checkNumbers;
    private JCheckBox checkSymbols;
    private JTextField txtOutput;

    private JTextField txtLimit;

    private final Misc misc = new Misc();

    private GUIMain() {
        //Date buildDate = new Date();
        //DateFormat dFormat = new SimpleDateFormat("yyyyMdd");
        this.setTitle("KDG Password Generator 1.0.2");
        int _height = 200;
        int _width = 450;
        this.setMinimumSize(new Dimension(_width, _height));
        this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        this.setResizable(false);
        gAbout.CreateBody();
        gAbout.setLocationRelativeTo(null);

        BufferedImage image = null;
        try {
            image = ImageIO.read(getClass().getResource("KDG_Logo.png"));
        } catch (IOException e) {
                e.printStackTrace();
        }
        setIconImage(image);

    }

    private void CreateMenu() {





        //Menu bar and the headers.
        JMenuBar mBar = new JMenuBar();
        JMenu mFile = new JMenu("File");
        mExit = new JMenuItem("Exit");
        mExit.addActionListener(new EventListener());
        JMenu mAbout = new JMenu("About");
        mProject = new JMenuItem("Project");
        mProject.addActionListener(new EventListener());
        mResetPref = new JMenuItem("Reset preferences");
        mResetPref.addActionListener(new EventListener());
        mSavePref = new JMenuItem("Save Preferences");
        mSavePref.addActionListener(new EventListener());

        //Right click menu.
        mContext = new JPopupMenu();
        mCopy = new JMenuItem("Copy");
        mCopy.addActionListener(new EventListener());
        mContext.add(mCopy);

        //Hotkeys.
        mFile.setMnemonic(KeyEvent.VK_F);
        mAbout.setMnemonic(KeyEvent.VK_A);
        mExit.setMnemonic((KeyEvent.VK_E));
        mProject.setMnemonic(KeyEvent.VK_P);
        mSavePref.setMnemonic(KeyEvent.VK_S);
        mResetPref.setMnemonic(KeyEvent.VK_R);

        //Add main headers to the bar.
        mBar.add(mFile);
        mBar.add(mAbout);

        //Add submenu items to main headers.
        mFile.add(mResetPref);
        mFile.add(mSavePref);
        mFile.add(mExit);
        mAbout.add(mProject);

        setJMenuBar(mBar);

    }

    private void CreateBody() {

        GridBagConstraints c = new GridBagConstraints();

        //Layout panels.
        JPanel fillerPanel = new JPanel();
        JPanel mainPanel1 = new JPanel(new GridLayout(2, 0));
        JPanel mainPanel2 = new JPanel(new BorderLayout());
        JPanel lPanel = new JPanel(new GridBagLayout());
        lPanel.setBorder(BorderFactory.createTitledBorder("Options"));
        JPanel mPanel = new JPanel(new BorderLayout());
        JPanel bPanel = new JPanel(new FlowLayout());
        JPanel rPanel = new JPanel(new GridBagLayout());
        rPanel.setBorder(BorderFactory.createTitledBorder("Set"));

        //Labels.
        JLabel labelLetters = new JLabel("Letters");
        JLabel labelNumbers = new JLabel("Numbers");
        JLabel labelSymbols = new JLabel("Symbols");
        JLabel labelLimit = new JLabel("<html>Size of Password <br>(3-20)</html>", SwingConstants.LEFT);
        JLabel labelClip = new JLabel("Copy to clipboard");
        labelClip.setToolTipText("If checked, each generate will automatically copy to clipboard");

        //Checkboxes.
        checkLetters = new JCheckBox();
        checkLetters.setSelected(userPrefs.getBoolean("letters", true));
        checkNumbers = new JCheckBox();
        checkNumbers.setSelected(userPrefs.getBoolean("numbers", true));
        checkSymbols = new JCheckBox();
        checkSymbols.setSelected(userPrefs.getBoolean("symbols", true));
        checkClip = new JCheckBox();
        checkClip.setToolTipText("If checked, each generate will automatically copy to clipboard");

        //Buttons.
        btnGenerate = new JButton("Generate");
        btnGenerate.setToolTipText("Each generate will copy to clipboard if selected");
        btnGenerate.addActionListener(new EventListener());
        btnExit = new JButton("Exit");
        btnExit.addActionListener(new EventListener());

        //Output.
        txtOutput = new JTextField();
        txtOutput.setOpaque(false);
        txtOutput.setBorder(BorderFactory.createEmptyBorder());
        txtOutput.setBackground(new Color(0, 0, 0, 0));
        txtOutput.setEditable(false);
        txtOutput.setHorizontalAlignment(JTextField.CENTER);
        txtOutput.addMouseListener(new MouseAdapter() {
            @Override
            public void mousePressed(MouseEvent e) {
                if (e.isPopupTrigger()) {
                    mContext.show(e.getComponent(), e.getX(), e.getY());
                }
            }

            //For Windows compatibility.
            @Override
            public void mouseReleased(MouseEvent e) {
                if (e.isPopupTrigger()) {
                    mContext.show(e.getComponent(), e.getX(), e.getY());
                }
            }

        });

        //Limit.
        txtLimit = new JTextField();
        txtLimit.setDocument(new JTextFieldLimit(2));
        txtLimit.setColumns(2);
        txtLimit.setText(userPrefs.get("limit", "7"));

        //consume letters or symbols.
        txtLimit.addKeyListener(new KeyAdapter() {
            @Override
            public void keyTyped(KeyEvent e) {
                char input = e.getKeyChar();

                if ((input <'0') || (input >'9')) {
                    e.consume();
                }
            }
        });

        //Ensure the text field always gets the first focus.
        addComponentListener(new ComponentAdapter() {
            @Override
            public void componentShown(ComponentEvent ce) {
                txtLimit.requestFocusInWindow();
            }
        });

        //http://www.youtube.com/watch?v=UuLaxbFKAcc

        //Left Panel setup.
        c.gridx = 0;
        c.gridy = 0;
        c.ipady = 25;
        c.ipadx = 25;
        c.anchor = GridBagConstraints.WEST;
        lPanel.add(labelLetters, c);

        c.gridx = 0;
        c.gridy = 1;
        c.ipady = 25;
        c.ipadx = 25;
        c.anchor = GridBagConstraints.WEST;
        lPanel.add(labelNumbers, c);

        c.gridx = 0;
        c.gridy = 2;
        c.ipady = 25;
        c.ipadx = 25;
        c.anchor = GridBagConstraints.WEST;
        lPanel.add(labelSymbols, c);

        c.gridx = 1;
        c.gridy = 0;
        c.ipady = 15;
        c.anchor = GridBagConstraints.WEST;
        lPanel.add(checkLetters, c);

        c.gridx = 1;
        c.gridy = 1;
        c.ipady = 15;
        c.anchor = GridBagConstraints.WEST;
        lPanel.add(checkNumbers, c);

        c.gridx = 1;
        c.gridy = 2;
        c.ipady = 15;
        c.anchor = GridBagConstraints.WEST;
        lPanel.add(checkSymbols, c);

        //Center panel setup.
        mPanel.add(txtOutput, BorderLayout.CENTER);
        mPanel.add(bPanel, BorderLayout.SOUTH);

        //right panel setup.
        c.gridx = 0;
        c.gridy = 0;
        c.ipady = 25;
        c.ipadx = 25;
        c.anchor = GridBagConstraints.WEST;
        rPanel.add(labelLimit, c);

        c.gridx = 0;
        c.gridy = 1;
        c.ipady = 25;
        c.ipadx = 25;
        c.anchor = GridBagConstraints.WEST;
        rPanel.add(labelClip, c);

        c.gridx = 1;
        c.gridy = 0;
        c.ipady = 0;
        c.ipadx = 0;
        c.anchor = GridBagConstraints.WEST;
        rPanel.add(txtLimit, c);

        c.gridx = 1;
        c.gridy = 1;
        c.ipady = 15;
        c.anchor = GridBagConstraints.WEST;
        rPanel.add(checkClip, c);

        //bottom panel layout.
        bPanel.add(btnGenerate);
        bPanel.add(btnExit);

        mainPanel2.add(fillerPanel, BorderLayout.NORTH);
        mainPanel2.add(lPanel, BorderLayout.WEST);
        mainPanel2.add(rPanel, BorderLayout.EAST);

        mainPanel1.add(mainPanel2);
        mainPanel1.add(mPanel);

        this.add(mainPanel1);

    }

    int getLimit() {

        //Suppressing warning from IDE.
        @SuppressWarnings("UnnecessaryLocalVariable")
        int limit = Integer.parseInt(txtLimit.getText());
        return limit;
    }

    private void SaveSettings() {
        int test = Integer.parseInt(txtLimit.getText());

        if ((!checkLetters.isSelected()) && (!checkNumbers.isSelected()) && (!checkSymbols.isSelected())) {
              //Do nothing.
        }
        else if (test <3 || test >20) {

            //Do nothing.

        } else {
            userPrefs.putBoolean("letters", checkLetters.isSelected());
            userPrefs.putBoolean("numbers", checkNumbers.isSelected());
            userPrefs.putBoolean("symbols", checkSymbols.isSelected());
            userPrefs.put("limit", txtLimit.getText());

        }
    }

    private void ResetSettings () {
        userPrefs.remove("letters");
        userPrefs.remove("numbers");
        userPrefs.remove("symbols");
        userPrefs.remove("limit");

        checkLetters.setSelected(true);
        checkNumbers.setSelected(true);
        checkSymbols.setSelected(true);
        txtLimit.setText("7");
        checkClip.setSelected(false);

    }

    //check limit input by user
    boolean checkLimit() {
        int limit = Integer.parseInt(txtLimit.getText());
        return !(limit < 3 || limit > 20);

    }

    private void doRandom() {
        boolean decide = checkLimit();
        if (decide) {
            misc.SetLimit(getLimit());
            if (checkSymbols.isSelected()) {
                misc.SetSymbols(true);
                txtOutput.setText(misc.GetSymbols());
            }

            if (checkLetters.isSelected()) {
                misc.SetLetters(true);
                txtOutput.setText(misc.GetLetters());
            }

            if (checkNumbers.isSelected()) {
                misc.SetNumbers(true);
                txtOutput.setText(misc.GetNumbers());

            }

            if (checkSymbols.isSelected() && checkLetters.isSelected()) {

                misc.SetLettersSymbols(true);
                txtOutput.setText(misc.GetRandomLettersSymbols());
            }
            if (checkNumbers.isSelected() && checkLetters.isSelected()) {
                misc.SetLettersNumbers(true);
                txtOutput.setText(misc.GetRandomLettersNumbers());
            }

            if (checkSymbols.isSelected() && checkNumbers.isSelected()) {

                misc.SetNumbersSymbols(true);
                txtOutput.setText(misc.GetRandomNumbersSymbols());
            }

            if (checkSymbols.isSelected() && checkLetters.isSelected() && checkNumbers.isSelected()) {
                misc.SetAll(true);
                txtOutput.setText(misc.GetRandomAll());
            }

        } else {
            JOptionPane.showMessageDialog(rootPane, "Limit must be more than 2 but less than 21");
            txtLimit.setText("7");
        }
    }

    class EventListener implements ActionListener {

        @Override
        public void actionPerformed(ActionEvent e) {



                if (e.getSource() == mExit || (e.getSource() == btnExit)) {
                    System.exit(0);

                } else if (e.getSource() == mProject) {
                    gAbout.setVisible(true);
                } else if (e.getSource() == mSavePref) {
                    SaveSettings();

                } else if ((e.getSource() == btnGenerate) && (!checkLetters.isSelected()) && (!checkNumbers.isSelected()) && (!checkSymbols.isSelected())) {
                    JOptionPane.showMessageDialog(rootPane, "No checkboxes selected!");

                } else if (e.getSource() == btnGenerate) {
                    doRandom();
                    if (checkClip.isSelected()) {
                        misc.SetClip(txtOutput.getText());
                    }
                } else if (e.getSource()== mCopy) {
                    misc.SetClip(txtOutput.getText());

                } else if (e.getSource() == mResetPref) {
                    ResetSettings();
                }

        }
    }

    //limit character amount in txtLmit
    class JTextFieldLimit extends PlainDocument {
        private final int limit;

        @SuppressWarnings("SameParameterValue")
        JTextFieldLimit(int limit) {
            super();
            this.limit = limit;
        }

        @Override
        public void insertString(int offset, String str, AttributeSet attr) throws BadLocationException {
            if (str == null)
                return;

            if ((getLength() + str.length()) <= limit) {
                super.insertString(offset, str, attr);

            }
        }


    }



    public static void main(String[] args) {
        GUIMain gMain = new GUIMain();

        try {
            UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (UnsupportedLookAndFeelException e) {
            e.printStackTrace();
        }

        gMain.CreateMenu();
        gMain.CreateBody();
        gMain.setLocationRelativeTo(null);
        gMain.pack();

        //Let the magic flow!
        gMain.setVisible(true);
    }

}








